package org.abettor.util;

import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;

/**
 * 用于动态扩展CLASSPATH的类
 * @author <a href="http://www.abettor.org/" target="_blank">abettor</a>
 *
 */
public class ClassPathLoader
{
	private static byte[] synLocker = new byte[0];
	private static ClassPathLoader instance;
	private URLClassLoader loader;
	private Method method;

	//	一个私有构造函数，全局只构造一个实例
	private ClassPathLoader() throws SecurityException, NoSuchMethodException
	{
		loader = (URLClassLoader) ClassLoader.getSystemClassLoader();
		Class<URLClassLoader> clazz = URLClassLoader.class;
		method = clazz.getDeclaredMethod("addURL", new Class[] {URL.class});
		method.setAccessible(true);
	}

	/**
	 * 将一个可以作为CLASSPATH的文件追加到程序搜索的CLASSPTH中
	 * @param file 要作为附加CLASSPATH搜索路径的文件对象
	 * @throws MalformedURLException
	 * @throws NoSuchMethodException 
	 * @throws SecurityException 
	 * @throws InvocationTargetException 
	 * @throws IllegalAccessException 
	 * @throws IllegalArgumentException 
	 */
	public static void addFile(File file) throws MalformedURLException, SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException
	{
		addURL(file.toURI().toURL());
	}

	/**
	 * 添加一个指定的URL对象到用于程序搜索Java类的URL列表，作为附加的CLASSPATH
	 * @param url 要添加到作为CLASSPATH的URL列表的URL对象，指向一个JAR文件或一个目录
	 * @throws NoSuchMethodException 
	 * @throws SecurityException 
	 * @throws InvocationTargetException 
	 * @throws IllegalAccessException 
	 * @throws IllegalArgumentException 
	 * @see java.net.URLClassLoader#addURL(URL)
	 */
	public static void addURL(URL url) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException
	{
		ClassPathLoader inst = getInstance();
		inst.method.invoke(inst.loader, new Object[] {url});
	}

	//	获取一个singleton实例
	private static ClassPathLoader getInstance() throws SecurityException, NoSuchMethodException
	{
		synchronized(synLocker)
		{
			if(instance == null)
			{
				instance = new ClassPathLoader();
			}
		}

		return instance;
	}
}
